/**
 * @author Gerd Wagner
 * @constructor
 * @this {ArithmeticProblem}
 * @param {ArithmeticProblemType} type  
 * @param {array} operands  The list of operands (depending on this.type.numberType,
 *        either integers, decimal numbers or fractions).
 * @param {object} result  Either an integer, decimal number or fraction.
 */
function ArithmeticProblem( type, operands, result) {
	this.type = new ArithmeticProblemType();
	this.operands = []; 
	this.result = 0; 

  if (arguments.length > 0) { // constructor invocation with arguments
    this.setType( type);
    this.setOperands( operands);
    this.setResult( result);
	}
}
ArithmeticProblem.prototype.setType = function( type) {
	if (!type) {
		throw new MandatoryValueConstraintViolation("No value provided for the parameter 'type'!"+
		    " operands = "+ operands +" result = "+ result);
	} else if (typeof(type) !== "object") {
		throw new TypeConstraintViolation("The parameter 'type' must be an object!");
	} else if (!(type instanceof ArithmeticProblemType)) {
		throw new TypeConstraintViolation("The parameter 'type' must represent an instance of ArithmeticProblemType!");
	} else {
		this.type = type;
	}
};
ArithmeticProblem.prototype.setOperands = function( operands) {
	if (operands === null) {
		throw new MandatoryValueConstraintViolation("No value provided for the parameter 'operands'!");
	} else if (!Array.isArray( operands)) {
		throw new TypeConstraintViolation("The parameter 'operands' must be an array!");
	} else if (operands.length < 2) {
		throw new MandatoryValueConstraintViolation("The parameter 'operands' is an array with less than 2 elements!");
	} else {
		this.operands = operands;
	}
};
ArithmeticProblem.prototype.setOperand = function( i, operand) {
	if (i<0) {
		throw new OtherConstraintViolation("Negative array index!");
//	} else if (!util.isInteger( operand)) {
//		throw new TypeConstraintViolation("The operand must be an integer!");
	} else {
		this.operands[i] = operand;
	}
};
ArithmeticProblem.prototype.setResult = function( result) {
	if (result === undefined) {
	  throw new MandatoryValueConstraintViolation("No value provided for result!");
//  } else if (typeof(result) !== "number") {
//    throw new TypeConstraintViolation("The value of result is not a number!");
  } else this.result = result;
};
/**
 * Determine what is the correct answer to a problem
 * 
 * @author Gerd Wagner
 * @return {number} The correct answer to a problem.
 */
ArithmeticProblem.prototype.getCorrectAnswer = function() {
  var askedFor = this.type.askedFor;
  if (askedFor === 0) { return this.result; }
  else { return this.operands[ askedFor-1]; }
};
/**
 * Determine if a given problem is equal to this problem
 * 
 * @author Gerd Wagner
 * @param {ArithmeticProblem} ap  The second problem
 * @return {boolean} True if both problems are equal.
 */
ArithmeticProblem.prototype.equals = function( ap) {
  var isEqual = true;
  if (this.type === ap.type) {
    for (var i=0; i < ap.operands.length; i++) { 
      isEqual = isEqual && (this.operands[i] === ap.operands[i]);
    }
    return isEqual; 
  }
  else { return false; }
};
/**
 * Determine what is the correct answer to a problem
 * 
 * @author Gerd Wagner
 * @return {number} The correct answer to a problem.
 */
ArithmeticProblem.prototype.isIncludedIn = function( problems) {
  for (var i=0; i < problems.length; i++) { 
    if (this.equals( problems[i])) { return true; }
  }
  return false;
};
/**
 * Tests if a problem is a basic addition or multiplication problem.
 * 
 * @author Gerd Wagner
 * @return {boolean}  
 */
ArithmeticProblem.prototype.isBasicProblem = function() {
  if (this.operands.length === 2 &&
      (this.type.operators[0] === OperatorEL.plus || this.type.operators[0] === OperatorEL.times) &&
      this.operands[0] >= 0 && this.operands[0] <= 9 &&
      this.operands[1] >= 0 && this.operands[1] <= 9 &&
      this.type.numberType != NumberTypeEL.Fraction &&
      (this.type.specialProblemCategory == null || this.type.specialProblemCategory == undefined)){ 
    return true; 
  } else {
    return false;
  }
};
